#include <iostream>
#include <cstdio>
#include <cstdlib>
/*#include <curses.h>*/
#include <cstring>

#include <unistd.h>

using namespace std;

#include "Memory.h"
#include "CPU.h"

/*void UpdateRegisterValues (WINDOW*, CPU*);
int lineCount = 0;

int main (int argc, char *argv[])
{
	WINDOW *regwin, *indexwin, *instwin, *cyclewin;
	char *title = "| Gemini Simulator |";
	char *cmd = "[Space - next cycle] [Enter - next instruction]";
	int width, height, ch, prevhit;
	int setch = 1; // select 1 way set associative or 2 way
	char *fname = NULL;
	bool execComplete = false;
	if (argc < 2) {
		cout << "USAGE: " << argv[0] << " filename" << endl;
		exit (1);
	}

	opterr = 1;
	while ((ch = getopt (argc, argv, "12f:")) != -1) {
		if (ch == '1') setch = 1;
		else if (ch == '2') setch = 2;
		else if (ch == 'f') {
			fname = optarg;
		}
	}

	if (fname == NULL) {
		cerr << "file name must be specified with -f <filename> option";
		exit (1);
	}

	CPU cpu (setch);

	initscr ();
	
	cbreak ();
	noecho ();
	
	width = COLS; height = LINES;
	regwin = subwin (stdscr, height-9 , (width)-8, 5, 4);
	box (regwin, 0, 0);
	box (stdscr, 0, 0);
	mvaddstr (0,(width-strlen(title))/2, title);
	mvaddstr (0,(width-15), "[ESC to quit]");
	mvaddstr (2, 4, "Instruction Index	:");
	mvaddstr (3, 4, "Instruction		:");
	mvaddstr (4, 4, "Binary Instruction	:");
	mvaddstr (2, 3*width/4, "Hit Count	:");
	mvaddstr (3, 3*width/4, "Miss Count	:");
	mvaddstr (4, 3*width/4, "Hit		:");
	mvaddstr (5, 7, "[Register]");
	mvaddstr (5, 26, "[Value]");
	mvaddstr (5, 45, "[Unused (for now)]");
	mvaddstr (height-3, 4, "Current Instruction Cycle	:");
	mvaddstr (height-1, (width-strlen(cmd))/2, cmd);
	mvwaddstr (regwin, 2, 5, "A");
	mvwaddstr (regwin, 3, 5, "B");
	mvwaddstr (regwin, 4, 5, "ACC");
	mvwaddstr (regwin, 5, 5, "ZERO");
	mvwaddstr (regwin, 6, 5, "ONE");
	mvwaddstr (regwin, 7, 5, "PC");
	mvwaddstr (regwin, 8, 5, "MAR");
	mvwaddstr (regwin, 9, 5, "MDR");
	mvwaddstr (regwin, 10, 5, "TEMP");
	mvwaddstr (regwin, 11, 5, "IR");
	mvwaddstr (regwin, 12, 5, "CC");

	UpdateRegisterValues (regwin, &cpu);

	cpu.Load (fname);
	prevhit = 0;
	do {
		ch = getch();

		if (!execComplete) {
			if (ch == ' ') { // modify to space
				//next cycle
				if (cpu.opNum == 1)
					cpu.Decode ();
				else if (cpu.opNum < cpu.opTotal)
					cpu.ExecuteNextCycle ();
				else {
					if (cpu.Fetch () == -1)
					execComplete = true;
				}
			} else if (ch == '\n') { //modify to enter
				//next instruction
				if (cpu.opNum >= cpu.opTotal) {
					if (cpu.Fetch () == -1)
					execComplete = true;
				}
				else if (cpu.opNum == 1)
					cpu.Decode ();
				else
					cpu.ExecuteNextInstruction ();
			} else if (ch == '\t') {
				// execute all instructions
				while (!execComplete)
				{
					if (cpu.opNum >= cpu.opTotal) {
						if (cpu.Fetch () == -1)
						execComplete = true;
					}
					else if (cpu.opNum == 1)
						cpu.Decode ();
					else
						cpu.ExecuteNextInstruction ();
				}
			}

			lineCount = cpu.IR;
			mvprintw(2,(width/2)-8,"%d/%d (%.0f%%)",
					cpu.IR,cpu.instrTotal,
					(float)(cpu.IR*100)/cpu.instrTotal);
			mvprintw(3,(width/2)-8,"                           ");
			mvprintw(3,(width/2)-8,"%s",
					cpu.currentOperation().c_str());
			mvprintw(4,(width/2)-8,"%s",
					cpu.binaryOperation().c_str());
			mvprintw(2,(3*width/4)+14,"%d",*(cpu.mem.nhit));
			mvprintw(3,(3*width/4)+14,"%d",*(cpu.mem.nmiss));	
			mvprintw(4,(3*width/4)+14,"%s",
				(*(cpu.mem.nhit)>prevhit)?"Yes":"No ");
			mvprintw(height-3,(width/2),"%d/%d [Operation]        ",
					cpu.opNum,cpu.opTotal); 
	       	
			UpdateRegisterValues (regwin, &cpu);
			wrefresh (regwin);
		}
		prevhit = *(cpu.mem.nhit);
		
	} while (ch != 27); //esc key

	endwin ();
	return 0;
}

void UpdateRegisterValues (WINDOW *regwin, CPU *cpu)
{
	mvwprintw (regwin, 2, 21, "[ 0x%08x ]", cpu->A);
	mvwprintw (regwin, 3, 21, "[ 0x%08x ]", cpu->B);
	mvwprintw (regwin, 4, 21, "[ 0x%08x ]", cpu->ACC);
	mvwprintw (regwin, 5, 21, "[ 0x%08x ]", cpu->ZERO);
	mvwprintw (regwin, 6, 21, "[ 0x%08x ]", cpu->ONE);
	mvwprintw (regwin, 7, 21, "[ 0x%08x ]", cpu->PC);
	mvwprintw (regwin, 8, 21, "[ 0x%08x ]", cpu->MAR);
	mvwprintw (regwin, 9, 21, "[ 0x%08x ]", cpu->MDR);
	mvwprintw (regwin, 10, 21, "[ 0x%08x ]", cpu->TEMP);
	mvwprintw (regwin, 11, 21, "[ 0x%08x ]", cpu->IR);
	mvwprintw (regwin, 12, 21, "[ 0x%08x ]", cpu->CC);
}*/

#ifdef _ABCD_
void errprintline (const char *msg, int line)
{
	//if (line == -1)
	//	line = lineCount;
	//mvprintw (1,5, "ERROR: %s at line %d", msg, line);
	//getch ();
	//endwin ();
	exit (1);
}
#endif 
